package net.flydy.ywxcx.wxcloudrun.config;

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.Expiry;
import org.checkerframework.checker.index.qual.NonNegative;
import org.springframework.cache.CacheManager;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author flydy
 */

@Configuration
public class LocalCacheConfig {
    public static final String CACHENAME_USER = "userCache";
    public static final String CACHENAME_DEFAULT = "default";

    /**
     * 创建基于Caffeine的Cache Manager
     * 初始化一些key存入
     *
     * @return
     */
    @Bean("cacheManager")
    @Primary
    public CacheManager caffeineCacheManager() {
        SimpleCacheManager cacheManager = new SimpleCacheManager();
        ArrayList<CaffeineCache> caches = new ArrayList<>();
        List<CacheBean> list = setCacheBean();
        for (CacheBean cacheBean : list) {
            caches.add(new CaffeineCache(cacheBean.getKey(),
                    Caffeine.newBuilder().recordStats()
                            .expireAfterWrite(cacheBean.getTtl(), TimeUnit.SECONDS)
                            .maximumSize(cacheBean.getMaximumSize())
                            .build()));
        }
        cacheManager.setCaches(caches);
        return cacheManager;
    }

    @Bean("selfCacheManager")
    public CacheManager selfCacheManager() {
        SimpleCacheManager cacheManager = new SimpleCacheManager();
        ArrayList<CaffeineCache> caches = new ArrayList<>();
        Cache<String, CacheEntity> mycalche  = Caffeine.newBuilder()
                .recordStats().maximumSize(10 * 10000)
//                .expireAfterWrite(4, TimeUnit.SECONDS)
                .expireAfter(new Expiry<String, CacheEntity>() {
                    @Override
                    public long expireAfterCreate(String key, CacheEntity value, long currentTime) {
                        return TimeUnit.SECONDS.toNanos(value.getTtl());
                    }
                    @Override
                    public long expireAfterUpdate(String key, CacheEntity value, long currentTime, @NonNegative long currentDuration) {
                        return TimeUnit.SECONDS.toNanos(value.getTtl());
                    }
                    @Override
                    public long expireAfterRead(String key, CacheEntity value, long currentTime, @NonNegative long currentDuration) {
                        //currentDuration 还剩余多少时间过期
//                        System.out.println("expireAfterRead "+TimeUnit.NANOSECONDS.toMillis(currentDuration));
                        return currentDuration;
                    }
                })
                .build();
        Cache cache = mycalche;
        caches.add(new CaffeineCache(CACHENAME_DEFAULT, cache));
        cacheManager.setCaches(caches);
        return cacheManager;
    }


    /**
     * 初始化一些缓存的 key
     *
     * @return
     */
    private List<CacheBean> setCacheBean() {
        List<CacheBean> list = new ArrayList<>();
        CacheBean userCache = new CacheBean();
        userCache.setKey(CACHENAME_DEFAULT);
        userCache.setTtl(60);
        userCache.setMaximumSize(10 * 10000);

        CacheBean deptCache = new CacheBean();
        deptCache.setKey(CACHENAME_USER);
        deptCache.setTtl(60);
        deptCache.setMaximumSize(10 * 10000);

        list.add(userCache);
        list.add(deptCache);

        return list;
    }

    class CacheBean {
        private String key;
        private long ttl;
        private long maximumSize;

        public String getKey() {
            return key;
        }

        public void setKey(String key) {
            this.key = key;
        }

        public long getTtl() {
            return ttl;
        }

        public void setTtl(long ttl) {
            this.ttl = ttl;
        }

        public long getMaximumSize() {
            return maximumSize;
        }

        public void setMaximumSize(long maximumSize) {
            this.maximumSize = maximumSize;
        }
    }

}
